using System;
using System.Threading.Tasks;
using StackExchange.Redis;

namespace CloudApiServer.helper;

/// <summary>
/// Redis 缓存操作类，支持指定数据库和分组
/// </summary>
public static class RedisHelper
{
    private static ConnectionMultiplexer _redisConnection;
    private static int _defaultDbIndex = 0; // 默认数据库索引
    private static string _keyPrefix = "";   // 默认键前缀（用于分组）

    /// <summary>
    /// 初始化 Redis 连接
    /// </summary>
    /// <param name="connectionString">Redis 连接字符串</param>
    /// <param name="defaultDbIndex">默认数据库索引</param>
    public static void Initialize(string connectionString, int defaultDbIndex = 0)
    {
        try
        {
            _redisConnection = ConnectionMultiplexer.Connect(connectionString);
            _defaultDbIndex = defaultDbIndex;
        }
        catch (Exception ex)
        {
            LogHelper.Error($"[RedisHelper.Initialize]Redis初始化异常！错误内容：{ex.Message} 异常堆栈{ex.StackTrace}");
            throw new Exception("无法连接到 Redis 服务器：" + ex.Message);
        }
    }

    /// <summary>
    /// 设置全局键前缀（用于分组）
    /// </summary>
    /// <param name="prefix">前缀名称（如 user、order 等）</param>
    public static void SetKeyPrefix(string prefix)
    {
        _keyPrefix = prefix;
    }

    /// <summary>
    /// 获取 Redis 数据库实例
    /// </summary>
    /// <param name="dbIndex">数据库索引（可选，默认为初始化时设置的值）</param>
    /// <returns>IDatabase 实例</returns>
    private static IDatabase GetDatabase(int? dbIndex = null)
    {
        if (_redisConnection == null)
        {
            throw new InvalidOperationException("Redis 连接未初始化，请先调用 Initialize 方法。");
        }
        return _redisConnection.GetDatabase(dbIndex ?? _defaultDbIndex);
    }

    /// <summary>
    /// 构建带前缀的 Key
    /// </summary>
    /// <param name="key">原始 Key</param>
    /// <param name="group">当前分组（若为空则使用全局前缀）</param>
    /// <returns>带前缀的完整 Key</returns>
    private static string BuildKey(string key, string group = null)
    {
        string effectiveGroup = !string.IsNullOrEmpty(group) ? group : _keyPrefix;
        return string.IsNullOrEmpty(effectiveGroup) ? key : $"{effectiveGroup}:{key}";
    }

    /// <summary>
    /// 异步新增或更新一个键值对到指定数据库
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <param name="expiry">过期时间（可选）</param>
    /// <param name="dbIndex">目标数据库索引（可选）</param>
    /// <param name="group">分组名（用于 key 的前缀）</param>
    /// <returns>是否成功设置</returns>
    public static async Task<bool> SetAsync(string key, string value, TimeSpan? expiry = null, int? dbIndex = null, string group = null)
    {
        var db = GetDatabase(dbIndex);
        var prefixedKey = BuildKey(key, group);
        return await db.StringSetAsync(prefixedKey, value, expiry);
    }

    /// <summary>
    /// 异步从指定数据库读取一个键的值
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="dbIndex">目标数据库索引（可选）</param>
    /// <param name="group">分组名（用于 key 的前缀）</param>
    /// <returns>对应的值</returns>
    public static async Task<string> GetAsync(string key, int? dbIndex = null, string group = null)
    {
        var db = GetDatabase(dbIndex);
        var prefixedKey = BuildKey(key, group);
        return await db.StringGetAsync(prefixedKey);
    }

    /// <summary>
    /// 异步删除指定数据库中的键
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="dbIndex">目标数据库索引（可选）</param>
    /// <param name="group">分组名（用于 key 的前缀）</param>
    /// <returns>是否成功删除</returns>
    public static async Task<bool> DeleteAsync(string key, int? dbIndex = null, string group = null)
    {
        var db = GetDatabase(dbIndex);
        var prefixedKey = BuildKey(key, group);
        return await db.KeyDeleteAsync(prefixedKey);
    }

    /// <summary>
    /// 异步设置指定数据库中键的过期时间
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="expiry">过期时间</param>
    /// <param name="dbIndex">目标数据库索引（可选）</param>
    /// <param name="group">分组名（用于 key 的前缀）</param>
    /// <returns>是否成功设置过期时间</returns>
    public static async Task<bool> ExpireAsync(string key, TimeSpan expiry, int? dbIndex = null, string group = null)
    {
        var db = GetDatabase(dbIndex);
        var prefixedKey = BuildKey(key, group);
        return await db.KeyExpireAsync(prefixedKey, expiry);
    }
}
